home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Graphics Unleashed
/
PC Graphics Unleashed.iso
/
ch03
/
morph.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-11
|
9KB
|
287 lines
/****************************************************************
* FILE: morph.c
* DESC: Create a metamorphosing sequence between two given
* images. This program lets you specify two files to
* morph, then prompts you for control lines. It uses
* the lines to warp the underlying images a step at
* a time, combine them, and optionally save them as
* numbered PCX files.
*
* HISTORY: Created 1/13/1993
* LAST CHANGED: 5/ 6/1993
*
* Copyright (c) 1993 by Scott Anderson
*
****************************************************************/
/* ----------------------INCLUDES----------------------------- */
#include <conio.h>
#include <stdio.h>
#include <io.h>
#include <math.h>
#include <graph.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include "define.h"
/* ----------------------DEFINES------------------------------ */
#define MORPH_TWEENS 1
/* ----------------------PROTOTYPES--------------------------- */
int tweenMorph(PICTURE *src, PICTURE *dst);
/* ----------------------EXTERNALS---------------------------- */
/**** color routines ****/
extern int closestColor(int r, int g, int b, PALETTE *palPtr);
extern void collapseColors(PALETTE *palPtr);
/**** line routines ****/
extern int setLength(LINE *line);
extern int sumLines(PICTURE *picture, COLOR *color,
LINE *origline, POINT *warp, LINE *warpline);
/**** io routines ****/
extern LINE_LIST *loadLines(char *filename, char *extension);
extern void saveLines(char *filename,
LINE_LIST *lineList, char *extension);
/***** variables used to compute intermediate images ****/
/* number of colors in tweened image before reduction*/
extern int Ncolors;
/* r, g, b frequency counter array */
extern unsigned int far Freq[MAX_COMP][MAX_COMP][MAX_COMP];
/* tweened images red, grn, and blu components*/
extern unsigned char far Red[MAX_WIDE][MAX_TALL];
extern unsigned char far Grn[MAX_WIDE][MAX_TALL];
extern unsigned char far Blu[MAX_WIDE][MAX_TALL];
extern PALETTE TweenPal; /* resulting palette */
/**** other variables ****/
extern char *OutFilename;
/* set from last picture loaded */
extern int Xmin, Ymin, Xmax, Ymax;
/* ID of palette currently being displayed */
extern int CurrentPal;
/* ----------------------GLOBAL DATA-------------------------- */
PICTURE *Src; /* source & destination picture pointers */
PICTURE *Dst;
LINE SrcLine[MAX_LINES];
LINE DstLine[MAX_LINES];
int Tweens;
int NumLines;
/*****************************************************************
* FUNC: main (int argc, char *argv[])
*
* DESC: Read in a filename to load
*****************************************************************/
main (int argc, char *argv[])
{
int segment;
LINE_LIST *lineSrcList;
LINE_LIST *lineDstList;
char answer;
/* load the pcx file if one is given */
if ((3 > argc) || (argc > 5)) {
printf("Usage: morph <source> <dest> [<steps> [<output>]]\n\n");
printf("Where: <source> is the source PCX filename\n");
printf(" <dest> is the destination filename\n");
printf(" <steps> is the optional sequence size\n");
printf(" (the max is %d, the default is %d)\n",
MAX_TWEENS, MORPH_TWEENS+2);
printf(" <output> is the optional output filename\n");
printf(" (defaults to no output)\n\n");
printf("Note: The output filename can be at most %d characters long.\n",
MAX_NAME_SIZE);
printf(" The PCX extension is added automatically, so don't\n");
printf(" include it in the filename.\n");
printf(" Morph only accepts PCX files with %d X %d resolution\n",
MAX_WIDE, MAX_TALL);
printf(" and %d colors.\n", COLORS);
exit(0);
}
if (argc > 3) {
/* subtract two from the series count to get the tweens
* since the starting and ending frame are included. */
Tweens = clip (atoi(argv[3]) - 2, 1, MAX_TWEENS);
if (argc > 4)
OutFilename = argv[4];
}
else
Tweens = MORPH_TWEENS;
printf("Loading the file %s\n", argv[1]);
Src = loadPicture(argv[1]);
if (Src == NULL)
quit(MEMORY_ERR, "");
printf("Loading the file %s\n", argv[2]);
Dst = loadPicture(argv[2]);
if (Dst == NULL)
quit(MEMORY_ERR, "");
lineSrcList = loadLines(argv[1], EXT_LINE1);
if (lineSrcList->number != 0) {
if (lineAsk(argv[1]) == 'N')
createLines(Src, lineSrcList);
else
editLines(Src, lineSrcList);
}
else
createLines(Src, lineSrcList);
TargFlag = 1; /* For the screen intro message */
NumLines = lineSrcList->number;
if (NumLines) {
lineDstList = loadLines(argv[2], EXT_LINE1);
/* inconsistent warp target*/
if (lineDstList->number != NumLines)
lineDstList->number = 0;
if (lineDstList->number) { /* ask what he wants to do */
if (lineAsk(argv[2]) == 'N')
lineDstList->number = 0;
}
if (lineDstList->number == 0) { /* create a warp target */
/* copy the source lines */
lineDstList->number = NumLines;
for (segment = 0; segment < NumLines; segment++)
lineDstList->line[segment]
= lineSrcList->line[segment];
}
editLines(Dst, lineDstList);
saveLines(argv[1], lineSrcList, EXT_LINE1);
saveLines(argv[2], lineDstList, EXT_LINE1);
beep();
for (segment = 0; segment < NumLines; segment++) {
DstLine[segment].p[0]=lineDstList->line[segment].p[0];
DstLine[segment].p[1]=lineDstList->line[segment].p[1];
setLength(&DstLine[segment]);
SrcLine[segment].p[0]=lineSrcList->line[segment].p[0];
SrcLine[segment].p[1]=lineSrcList->line[segment].p[1];
setLength(&SrcLine[segment]);
}
}
tweenMorph(Src, Dst);
setTextMode();
}
/*****************************************************************
* FUNC: int tweenMorph(PICTURE *src, PICTURE *dst)
*
* DESC: calculate a pixel to plot, from the warping function
*****************************************************************/
#define TOTAL_WEIGHT (100) /* Good for up to 99 tweens */
tweenMorph(PICTURE *src, PICTURE *dst)
{
int color;
POINT warp;
int x,y;
COLOR scolor, dcolor;
LINE warpLine[MAX_LINES];
int t, i, p;
int r, g, b;
unsigned int srcweight, srcpaletteindex;
unsigned int dstweight, dstpaletteindex;
displayPicture(src);
saveScreen(&src->pal);
/* src is on screen, now tween to the target */
for (t = 1; t <= Tweens; t++) {
/* Tween the lines used to warp the images */
for (i = 0; i < NumLines; i++) {
for (p = 0; p < 2; p++) {
warpLine[i].p[p].x = SrcLine[i].p[p].x +
((DstLine[i].p[p].x - SrcLine[i].p[p].x) * t)
/(Tweens+1);
warpLine[i].p[p].y = SrcLine[i].p[p].y +
((DstLine[i].p[p].y - SrcLine[i].p[p].y) * t)
/(Tweens+1);
}
setLength(&warpLine[i]);
}
dstweight = t * TOTAL_WEIGHT / (Tweens+1);
srcweight = TOTAL_WEIGHT - dstweight;
/* Zero out the buffers */
initFreq();
/* set background to black */
_fmemset(Red, 0, sizeof Red);
_fmemset(Grn, 0, sizeof Grn);
_fmemset(Blu, 0, sizeof Blu);
/* Go through the screen and get warped source pixels */
for (warp.y = Ymin; warp.y <= Ymax; warp.y++) {
if (quitCheck())
quit(0, "");
for (warp.x = Xmin; warp.x <= Xmax; warp.x++) {
sumLines(src, &scolor, SrcLine, &warp, warpLine);
sumLines(dst, &dcolor, DstLine, &warp, warpLine);
r = (scolor.r * srcweight + dcolor.r * dstweight)
/ TOTAL_WEIGHT;
g = (scolor.g * srcweight + dcolor.g * dstweight)
/ TOTAL_WEIGHT;
b = (scolor.b * srcweight + dcolor.b * dstweight)
/ TOTAL_WEIGHT;
if (Freq[r][g][b] == 0) /* A new color */
Ncolors++;
/* Keep it to one byte */
if (Freq[r][g][b] < MAX_FREQ)
Freq[r][g][b]++;
/* put RGB components into temporary buffer */
Red[warp.x][warp.y] = r;
Grn[warp.x][warp.y] = g;
Blu[warp.x][warp.y] = b;
}
}
collapseColors(&TweenPal);
setPalette(&TweenPal);
for (y = Ymin; y <= Ymax; y++) {
if (quitCheck())
quit(0, "");
for (x = Xmin; x <= Xmax; x++) {
color = closestColor( Red[x][y],
Grn[x][y],
Blu[x][y],
&TweenPal);
_setcolor (color);
_setpixel (x, y);
}
}
/* no output file name on command line */
if (!OutFilename) {
beep();
waitForKey(); /* so pause to enjoy the pictures */
}
else
saveScreen(&TweenPal);
}
if (OutFilename) { /* save the last pic in this series */
CurrentPal = 0; /* force a new palette */
displayPicture(dst);
saveScreen(&dst->pal);
}
}